package com.dong.es.entity.dtocast;


import com.dong.es.anno.DTOCastAnno;
import com.dong.es.entity.EsBaseDTO;
import com.dong.es.entity.EsViewDTO;

/**
 * EsViewDTO 转成 EsBaseDTO 的基类
 * 和注解{@link DTOCastAnno} 共同使用，
 * 详情见{@link DTOCastAnno}
 *
 * @description: 转换方法的抽象类，前端参数 转成 查询参数
 * @author: 陈瑞东
 * @create: 2022-06-21 09:38
 */
public abstract class DTOCastMethod {

    /**
     * 转换方法
     * @param viewDTO 用户操作的对象
     * @param baseDTO ES查询参数对象
     */
    public void cast(EsViewDTO viewDTO, EsBaseDTO baseDTO, Object... args) {
        // 校验参数
        if(argsValid(args)) {
            load(args);
            doCast(viewDTO, baseDTO);
        }
    }

    /**
     * 校验参数
     * @param args 参数
     * @return 校验是否通过
     */
    private boolean argsValid(Object... args) {
        // 获取参数限制，如果为null，则不限制
        Integer size = sizeLimit();
        // 校验参数数量
        if (size != null && args.length != size) {
            return false;
        }

        // 获取参数类型限制数组，如果该下标为null，则跳过比对
        Class[] clazz = typeLimit();
        for (int i = 0; clazz != null && i < clazz.length; i++) {
            // 如果该下标值为null，则跳过本次比对
            if (clazz[i] == null) {
                continue;
            }
            // 获取当前下标参数值
            Object arg = args[i];
            // 判断参数值是否为null
            if (arg == null) {
                // 查看是否可以忽略null的参数值，如果可以，则继续下次循环
                if (isIgnoreNull()) {
                    continue;
                }
                return false;
            }
            // 比对参数是否是指定的类型，如果不是，则不通过
            if (!classEqual(arg.getClass(), clazz[i])) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断类型是否相等或者继承关系
     * @param param 入参类型（只能是子类型或者相同类型）
     * @param base 基础类型（只能是父类型或者相同类型）
     * @return 类型是否相等
     */
    private boolean classEqual(Class param, Class base) {
        if (param == null) {
            return false;
        }
        if (param != base) {
            // 判断继承的接口是否匹配
            for (Class anInterface : param.getInterfaces()) {
                if (true == classEqual(anInterface, base)) {
                    return true;
                }
            }
            return classEqual(param.getSuperclass(), base);
        }
        return true;
    }

    /**
     * 参数数组大小限制
     * @return 数组大小，如果为null，则不限制
     */
    protected abstract Integer sizeLimit();

    /**
     * 参数类型限制
     * @return 参数类型数组，如果为某下标为null，则跳过该下标的比对
     */
    protected abstract Class[] typeLimit();

    /**
     * 加载属性
     * @param args 参数
     */
    protected abstract void load(Object... args);

    /**
     * 执行转换
     * @param viewDTO 用户操作的对象
     * @param baseDTO ES查询的参数对象
     */
    protected abstract void doCast(EsViewDTO viewDTO, EsBaseDTO baseDTO);

    /**
     * 是否忽略null值
     * @return 是否可以忽略null值
     */
    public boolean isIgnoreNull() {
        return false;
    }
}
